import { tool } from "newrow-utils/dist/src/tool";
import { CGFORMAT } from "./CGFORMAT";

//GLSL转CG
export namespace Transformer {
    type TransformParagraph = [string | RegExp, string];

    //基础转换规则
    const Transforms: TransformParagraph[] = [
        [/uniform (lowp|mediump|highp) sampler2D/g, 'uniform sampler2D'],
        [/uniform (lowp|mediump|highp) samplerCube/g, 'uniform samplerCUBE'],

        [/vec\d\((\S+)\)/g, '$1'],
        [/(\n\s+)vec(\d)/g, '$1float$2'],
        [/bvec(\d)/g, 'bool$1'],
        [/ivec(\d)/g, 'int$1'],
        [/uvec(\d)/g, 'uint$1'],
        [/lowp\s+float/g, 'fixed'],
        [/mediump\s+float/g, 'half'],
        [/highp\s+float/g, 'float'],
        [/lowp\s+vec(\d)/g, 'fixed$1'],
        [/mediump\s+vec(\d)/g, 'half$1'],
        [/highp\s+vec(\d)/g, 'float$1'],

        [/uniform\s+vec(\d)/g, 'uniform float$1'],
        [/uniform\s+mediump vec(\d)/g, 'uniform half$1'],
        [/uniform\s+/g, 'uniform '],

        [/texture\(/g, 'tex2D('],
        [/fract\(/g, 'frac('],
        [/mod\(/g, 'fmod('],
        [/texture2D\(/g, 'tex2D('],
        [/inversesqrt\(/g, 'rsqrt('],
        [/mix\(/g, 'lerp('],
        [/textureCube\(/g, 'texCUBE('],
        [/lessThan\((\S+), (\S+)\)/g, '($1 < $2)'],
        [/vec(\d)\(/g, 'float$1('],
        [/ivec(\d)\(/g, 'int$1('],
        [/uvec(\d)\(/g, 'uint$1('],
        [/bvec(\d)\(/g, 'bool$1('],

        [/in_POSITION0/g, 'input.position0'],
        [/in_COLOR(\d)/g, 'input.color$1'],
        [/in_NORMAL(\d)/g, 'input.normal$1'],
        [/in_TEXCOORD(\d)/g, 'input.texcoord$1'],
        [/in_TANGENT(\d)/g, 'input.tangent$1'],

        [/gl_Position/g, 'output.position'],
        [/vs_COLOR(\d)/g, 'output.color$1'],
        [/vs_NORMAL(\d)/g, 'output.normal$1'],
        [/vs_TEXCOORD(\d)/g, 'output.texcoord$1'],
        [/vs_TANGENT(\d)/g, 'output.tangent$1'],
    ]

    export function TransformParagraph(text: string) {
        let trans: TransformParagraph;
        for (let i = 0, length = Transforms.length; i < length; i++) {
            trans = Transforms[i];
            text = text.replace(trans[0], trans[1]);
        }
        return text;
    }

    //语法结构转换规则
    const GLSLRegs = {
        Uniform: /uniform \S+ \S+;/g,
        in: /(in|attribute) (\S+) input.(\S+)(\d+);/g,
        out: /(out|varying) (\S+) output.(\S+)(\d+);/g,
        vertVars: /(?<=(out|varying|in|attribute) \S+ \S+;\n)([\w\W]+?)void/gm,
        fragVars: /(layout\(location = 0\)|#define SV_Target0)[\w\W]+?\n([\w\W]+)void/g,
        code: /\{([\w\W]+)\s+\}/g,
    }

    function INPUT_OUTPUT(regArray: RegExpMatchArray[]) {
        let results: string[] = [];
        for (let i = 0, length = regArray.length; i < length; i++) {
            let input = regArray[i];
            let type = input[2];
            let name = input[3];
            let index = input[4];
            let fitName: string = '';
            if (name == 'texcoord')
                fitName = `${name.toUpperCase()}${index}`;
            else
                fitName = `${name.toUpperCase()}`;
            let result = `\t\t\t\t${type} ${name}${index} : ${fitName};`;
            results.push(result);
        }
        return results.join('\n');
    }

    function GLSL2CGVert(text: string) {
        text = TransformParagraph(text);

        let ins = [...text.matchAll(GLSLRegs.in)];
        let outs = [...text.matchAll(GLSLRegs.out)];

        let uniforms = [...text.matchAll(GLSLRegs.Uniform)]
            .map(i => '\t\t\t' + i[0])
            .join('\n');

        let codeStatement = [...text.matchAll(GLSLRegs.code)]?.[0]?.[1]
            .replace('return;', '')
            .replace(/[\n\t]+\s+/g, '\n\t\t\t\t');

        let vars = [...text.matchAll(GLSLRegs.vertVars)]?.[0]?.[2]
            .replace(GLSLRegs.out, '')
            .replace(GLSLRegs.in, '')
            .replace(/\t+\n/g, '')
            .replace(/[\n\t]+\s+/g, '\n\t\t\t\t');

        return [uniforms, INPUT_OUTPUT(ins), INPUT_OUTPUT(outs), vars, codeStatement];
    }

    function GLSL2CGFrag(text: string) {
        text = TransformParagraph(text);

        let uniforms = [...text.matchAll(GLSLRegs.Uniform)]
            .map(i => '\t\t\t' + i[0])
            .join('\n');

        let codeStatement = [...text.matchAll(GLSLRegs.code)][0][1]
            .replace('return;', '')
            .replace(/[\n\t]+\s+/g, '\n\t\t\t\t');

        let vars = [...text.matchAll(GLSLRegs.fragVars)]?.[0]?.[2]
            .replace(/[\n\t]+\s+/g, '\n\t\t\t\t');

        return [uniforms, vars, codeStatement];
    }

    export function GLSL2CG(textVert: string, textFrag: string) {
        let [vertUniforms, vertInput, vertOutput, vertVars, vertCode] = GLSL2CGVert(textVert);
        let [fragUnifroms, fragVars, fragCode] = GLSL2CGFrag(textFrag);
        let result = tool.StringFormat(
            CGFORMAT,
            vertInput,
            vertOutput,
            [vertUniforms, fragUnifroms].join('\n'),
            vertVars,
            vertCode,
            fragVars,
            fragCode,
        );
        return result;
    }

}